#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 11-Nov-09 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;

using Thn;
using System.Reflection;
#endregion

namespace Thn.Interface.Vcl
{
    /// <summary>
    /// This control allows picking a value from a popped-up list.
    /// </summary>
    [ToolboxItem(true), DefaultProperty("Text"), DefaultEvent("SelectedIndexChanged"), ToolboxBitmap(typeof(ResourceBeacon), "Thn.Interface.Vcl.Resources.Icons.PopupListBox.bmp")]
#if DEBUG
    public
#else
    public
#endif
 class PopupListBox : OldPopupBoxBase
    {
        #region Fields
        /// <summary>
        /// Turn on this flag for suppress auto complete fill event.
        /// </summary>
        protected bool mSupressAutoCompleteFillIn = false;
        /// <summary>
        /// Turn on this flag for suppress auto complete functionality.
        /// </summary>
        protected bool mSuppressAutoComplete = false; 
        #endregion

        #region Properties

        #region Behavior

        #region Items
        private ListBoxItemList mItems = null;
        /// <summary>
        /// Gets/Sets list box's items.
        /// </summary>
        [Browsable(true), DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Value")]
        public ListBoxItemList Items
        {
            get
            {
                if (mItems == null)
                {
                    mItems = new ListBoxItemList();
                    //mItems.mParentListbox = this;
                }
                return mItems;
            }
            set
            {
                mItems = value;
                //mItems.mParentListbox = this;

                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Columns
        private ListBoxColumnList mColumns = null;
        /// <summary>
        /// Gets/Sets listbox's columns.
        /// </summary>
        [Browsable(true), DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Appearance")]
        public ListBoxColumnList Columns
        {
            get
            {
                if (mColumns == null)
                {
                    mColumns = new ListBoxColumnList();
                }
                #region Defensive
                else
                {
                    // do nothing.
                }
                #endregion
                return mColumns;
            }
            set
            {
                mColumns = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Selected Index
        /// <summary>
        /// Index of currently selected row
        /// </summary>
        protected int mSelectedIndex = -1;
        /// <summary>
        /// Gets/Sets index of selected item
        /// </summary>
        [Browsable(true), DefaultValue(-1), Category("Value")]
        public int SelectedIndex
        {
            get { return mSelectedIndex; }
            set
            {
                SetSelectedIndex(value);
                if ((mSelectedIndex >= 0) && (mSelectedIndex < mItems.Count))
                {                    
                    OnSelectedIndexChanged();
                    RaiseSelectedIndexChanged(EventArgs.Empty);
                }
            }
        }
        #endregion

        #region Selected Item
        /// <summary>
        /// Gets value of the item which is being seleted.
        /// </summary>
        [Browsable(true), DefaultValue(null), Category("Bihavior"), Description("Value of the item is being seleted.")]
        public ListBoxItem SelectedItem
        {
            get 
            {
                ListBoxItem result = null;

                if (mSelectedIndex >= 0 && mSelectedIndex < mItems.Count)
                {
                    result = mItems[mSelectedIndex];
                }
                #region Defensive tracing
                else
                {
                    // out of range, return null.
                }
                #endregion

                return result; 
            }
        }
        #endregion  

        #region Selected value
        object mSelectedValue = null;
        /// <summary>
        /// Gets/Sets the value of currently selected item
        /// </summary>
        [Browsable(false), DefaultValue(null)]
        public object SelectedValue
        {
            get
            {
                return mSelectedValue;
            }
            set
            {
                int oldIdx = mSelectedIndex;
                mSelectedValue = value;

                if (value == null) this.Text = "";
                else
                {
                    ListBoxItem item = FindItem(value);

                    //match index
                    if (item == null) mSelectedIndex = -1;
                    else
                    {
                        for (int i = 0; i < mItems.Count; i++)
                        {
                            if (mItems[i] == item)
                            {
                                mSelectedIndex = i;
                                break;
                            }
                        }
                    }
                    if (item == null) this.Text = "";
                    else this.Text = item.Text;
                }

                //raise event
                if (mSelectedIndex != oldIdx)
                {
                    OnSelectedIndexChanged();
                    RaiseSelectedIndexChanged(EventArgs.Empty);
                }
            }
        }
        #endregion

        #region Auto Complete
        bool mAutoComplete = true;
        /// <summary>
        /// Gets or Sets auto-lookup when typing
        /// </summary>
        [Browsable(true), Description("Automatically lookup when typing"), DefaultValue(true), Category("Behavior")]
        protected bool AutoComplete
        {
            get { return mAutoComplete; }
            set
            {
                mAutoComplete = value;
            }
        }
        #endregion

        #region Has Sub Items
        /// <summary>
        /// True if need to check Has Sub Items again.
        /// </summary>
        protected bool mRecalculateHasSubItems = true;
        bool mHasSubItems = false;

        /// <summary>
        /// Checks whether this listbox has sub-items => draw as tree instead of list
        /// </summary>
        protected bool HasSubItems
        {
            get
            {
                if (mRecalculateHasSubItems)
                {
                    mHasSubItems = FindSubItems();
                    mRecalculateHasSubItems = false;
                }
                return mHasSubItems;
            }
        }

        /// <summary>
        /// Iterate throw all items in main list to see if I need to draw as a tree instead of a list
        /// </summary>
        bool FindSubItems()
        {

            bool result = false;
            if (mItems != null)
            {
                for (int i = 0; i < mItems.Count; i++)
                {
                    if ((mItems[i].Children != null) && (mItems[i].Children.Count > 0))
                    {
                        //as long as any item has a children, that is enough to draw as tree instead of list
                        result = true;
                        break;
                    }
                }
            }
            return result;
        }
        #endregion

        #endregion        

        #region Visuals

        #region Row Height
        private int mRowHeight = 24;
        /// <summary>
        /// Gets/Sets height of each row.
        /// </summary>
        [Browsable(true), DefaultValue(24), Category("Appearance")]
        public int RowHeight
        {
            get { return mRowHeight; }
            set
            {
                mRowHeight = value;

                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Draw Title
        private bool mDrawTitle = false;
        /// <summary>
        /// Gets/Sets whether draw title of columns.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Appearance")]
        public bool DrawTitle
        {
            get { return mDrawTitle; }
            set
            {
                mDrawTitle = value;

                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Title Height
        private int mTitleHeight = 24;
        /// <summary>
        /// Gets/Sets height of column title row.
        /// </summary>
        [Browsable(true), DefaultValue(24), Category("Appearance")]
        public int TitleHeight
        {
            get { return mTitleHeight; }
            set
            {
                mTitleHeight = value;

                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Text Style
        /// <summary>
        /// Gets/Sets font style for rendering text.
        /// </summary>
        [Browsable(true), DefaultValue(TextStyle.Normal), Category("Appearance"), Description("Font style for rendering text")]
        public TextStyle TextStyle
        {
            get { return RenderContext.TextStyle; }
            set
            {
                RenderContext.TextStyle = value;
                InvalidateRenderation();
            }
        }
        #endregion

        #region Title Text Style
        private TextStyle mTitleTextStyle = TextStyle.Normal;
        /// <summary>
        /// Gets/Sets font style for rendering text.
        /// </summary>
        [Browsable(true), DefaultValue(TextStyle.Normal), Category("Appearance"), Description("Font style for rendering title")]
        public TextStyle TitleTextStyle
        {
            get { return mTitleTextStyle; }
            set
            {
                mTitleTextStyle = value;
                InvalidateRenderation();
            }
        }
        #endregion

        #region Draw Check
        private bool mDrawCheck = false;
        /// <summary>
        /// Gets/Sets whether draw checkbox for Checked items.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Appearance")]
        public bool DrawCheck
        {
            get { return mDrawCheck; }
            set { mDrawCheck = value; }
        }
        #endregion

        #region Sign Pad
        private int mSignPad = 18;
        /// <summary>
        /// Gets/Sets padding for plus/minus sign.
        /// </summary>
        [Browsable(true), DefaultValue(18), Category("Appearance")]
        public int SignPad
        {
            get { return mSignPad; }
            set
            {
                mSignPad = value;

                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Padding
        private int mPadding = 3;
        /// <summary>
        /// Gets/Sets row padding.
        /// </summary>
        [Browsable(true), DefaultValue(3), Category("Appearance")]
        public int Padding
        {
            get { return mPadding; }
            set
            {
                mPadding = value;
                // invalidate layout
                InvalidateLayout();
            }
        }
        #endregion

        #region Auto-Sized Column
        private int mAutoSizedColumn = 0;
        /// <summary>
        /// Gets/Sets index of column that will be auto-resized.
        /// </summary>
        [Browsable(true), DefaultValue(0), Category("Appearance")]
        public int AutoSizedColumn
        {
            get { return mAutoSizedColumn; }
            set { mAutoSizedColumn = value; }
        }
        #endregion

        #region Is Show Popup On Key Press
        /// <summary>
        /// Gets or Sets value determine whether the popup edit will be showed or not when user press Enter key.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Appearance"), Description("Allow show popup edit when user press Enter key or not.")]
        public bool IsShowPopupOnKeyPress
        {
            get { return mIsShowPopupOnKeyPress; }
            set { mIsShowPopupOnKeyPress = value; }
        }
        #endregion

        #region Show Button
        /// <summary>
        /// Gets/Sets whether this box should show a drop down button.
        /// </summary>
        [Browsable(true), DefaultValue(true), Category("Appearance"), Description("Display drop down button")]
        public bool ShowDropButton
        {
            get { return mShowDropButton; }
            set
            {
                mShowDropButton = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Even Item Background Color
        Color mEvenItemBackgroundColor = Color.White;
        /// <summary>
        /// Gets or Sets background color of even items.
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("Background color of even items.")]
        public Color EvenItemBackgroundColor
        {
            get { return mEvenItemBackgroundColor; }
            set { mEvenItemBackgroundColor = value; }
        }
        #endregion

        #region Odd Item Backgound Color
        Color mOddItemBackgoundColor = Color.FromArgb(238, 238, 238);
        /// <summary>
        /// Gets or Sets background color of odd items.
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("Background color of odd items.")]
        public Color OddItemBackgoundColor
        {
            get { return mOddItemBackgoundColor; }
            set { mOddItemBackgoundColor = value; }
        }
        #endregion  

        #endregion

        #endregion        

        #region Events

        #region Selected Index Changed
        /// <summary>
        /// This event is raised after selected index changed.
        /// </summary>
        public event EventHandler SelectedIndexChanged;

        /// <summary>
        /// Invoke event SelectedIndexChanged.
        /// </summary>
        protected void RaiseSelectedIndexChanged(EventArgs args)
        {
            EventHandler handler = SelectedIndexChanged;
            if (handler != null) handler(this, args);
        }
        #endregion

        #endregion

        #region Inner Events

        #region Notify On Key Press
        /// <summary>
        /// Override this method for process auto complete func.
        /// </summary>
        internal override void NotifyInnerTextBoxOnKeyPress(KeyPressEventArgs e)
        {
            if (mAutoComplete)
            {
                if (e.KeyChar == (int)Keys.Escape)
                {
                    mSuppressAutoComplete = true;
                    if (IsPopping) CancelPopup();
                    e.Handled = true;
                }
                else if (e.KeyChar == (int)Keys.Enter)
                {
                    if ((mAutoComplete) && (IsPopping))
                    {
                        AcceptPopup();
                        mSuppressAutoComplete = true;
                    }
                    e.Handled = true;
                }
                else if (e.KeyChar == (int)Keys.Back)
                {
                    mSuppressAutoComplete = false;
                    mSupressAutoCompleteFillIn = true;
                }
                else if (Char.IsControl(e.KeyChar))
                {
                    mSuppressAutoComplete = true;
                }
                else mSuppressAutoComplete = false;
            }//auto-complete

            if ((!e.Handled) && (!IsPopping)) ShowPopup();
        }
        #endregion

        #region Notify On Text Changed
        /// <summary>
        /// Override this method for process the auto complete functionality.
        /// </summary>
        internal override void NotifyInnerTextBoxOnTextChanged()
        {
            if (mAutoComplete && IsPopping)
            {
                ListBoxPopupEditor lst = (ListBoxPopupEditor)Controller.Editor;
                if (lst.Items.Count > 0)
                {//lst has items
                    if (Inner.Text != "" && !mSuppressAutoComplete)
                    {
                        //search for matching entry
                        string key = Inner.Text;

                        for (int i = 0; i < lst.Items.Count; i++)
                        {
                            int tmp = string.Compare(key, 0, lst.Items[i].Text, 0, key.Length, true);
                            if (string.Compare(key, 0, lst.Items[i].Text, 0, key.Length, true, System.Globalization.CultureInfo.InvariantCulture) == 0)
                            {
                                lst.SetSelectedIndex(i);
                                lst.Invalidate();
                                if (!mSupressAutoCompleteFillIn)
                                {
                                    Inner.Text = lst.Items[i].Text;
                                    Inner.SelectionStart = key.Length;
                                    Inner.SelectionLength = Inner.Text.Length - key.Length;
                                }
                                break;
                            }
                        }//for
                    }//text not null
                    else
                    {
                        lst.SetSelectedIndex(-1);
                        lst.Invalidate();
                    }

                    this.Focus();
                }//lst has items
            }//auto-complete
        }
        #endregion

        #region Notify Process Cmd Key
        /// <summary>
        /// Override this method for process show or hide the popup editor when user used cmd key.
        /// </summary>
        internal override bool NotifyProcessCmdKey(ref Message msg, Keys keyData)
        {
            
            bool result = base.NotifyProcessCmdKey(ref msg, keyData);

            if (Controller != null)
            {
                ListBoxPopupEditor lst = (ListBoxPopupEditor)Controller.Editor;

                if (!result)
                {
                    switch (keyData)
                    {
                        case Keys.Up:
                            if (IsPopping)
                            {
                                if (lst.SelectedIndex > 0)
                                {
                                    lst.SetSelectedIndex(lst.SelectedIndex - 1);
                                }
                                result = true;
                            }
                            else
                            {
                                ShowPopup();
                                this.Focus();
                            }
                            break;

                        case Keys.Down:
                            if (IsPopping)
                            {
                                if (lst.SelectedIndex < lst.Items.Count - 1)
                                {
                                    lst.SetSelectedIndex(lst.SelectedIndex + 1);
                                }
                                result = true;
                            }
                            else
                            {
                                ShowPopup();
                                this.Focus();
                            }
                            break;
                    }
                }
            }

            return result;
        }
        #endregion

        #endregion

        #region Public methods

        #region Set Selected Index
        /// <summary>
        /// Sets selected index, support ensure visible.
        /// </summary>
        public void SetSelectedIndex(int idx)
        {
            if (!DesignMode)
            {
                mSelectedIndex = idx;
                if ((mSelectedIndex >= 0) && (mSelectedIndex < mItems.Count))
                {
                    Text = mItems[mSelectedIndex].Text;
                    mSelectedValue = mItems[mSelectedIndex].Value;
                    Inner.SelectionLength = 0;
                    Inner.SelectionStart = Inner.Text.Length;
                }
                else
                {
                    Text = string.IsNullOrEmpty(TextWhenNull) ? string.Empty : TextWhenNull;
                }

                //invalidate popup
                if ((IsPopping) && (Controller != null))
                {
                    ListBoxPopupEditor lst = (ListBoxPopupEditor)Controller.Editor;
                    lst.SetSelectedIndex(mSelectedIndex);
                    lst.Invalidate();
                }
            }
            #region Defensive tracing
            else
            {
                // do nothing in design mode.
            }
            #endregion
        }
        #endregion

        #endregion

        #region Popup

        #region On Popup Accepted
        /// <summary>
        /// This method is raised after the user closed popup editor and wish to accept modifications on editor
        /// </summary>
        /// <param name="popup">The controller which manages the popup</param>
        protected override void OnPopupAccepted(PopupController popup)
        {
            ListBoxPopupEditor lst = (ListBoxPopupEditor)popup.Editor;
            //if (mSelectedIndex != lst.SelectedIndex) // old code
            // Tln modify on 09 - 05 - 2008
            if ((mSelectedIndex != lst.SelectedIndex) && (lst.SelectedIndex != -1))
            {
                mSelectedIndex = lst.SelectedIndex;
                mSelectedValue = lst.SelectedValue;
                ListBoxItem item = lst.SelectedItem;
                if (item == null) Text = "";
                else Text = item.Text;

                //raise event
                OnSelectedIndexChanged();
                RaiseSelectedIndexChanged(EventArgs.Empty);
            }
        }
        #endregion

        #region On Show Popup
        /// <summary>
        /// This method is raised before a popup is shown. Override this method to assign the data that is going to be used by popup editor
        /// </summary>
        /// <param name="popup">The controller which manages the popup</param>
        protected override void OnShowPopup(PopupController popup)
        {
            popup.Data = this.SelectedValue;
        }
        #endregion

        #region On Get Popup Width
        /// <summary>
        /// Calculate the popup width
        /// </summary>
        protected override int OnGetPopupWidth()
        {
            int result = base.OnGetPopupWidth();

            if (result <= 0)
            {
                if ((mColumns != null) && (mColumns.Count > 1))
                {
                    for (int i = 0; i < mColumns.Count; i++)
                    {
                        result += mColumns[i].Width;
                    }

                    //add scrollbar size
                    result += 30;
                }
                else result = this.Width;
            }

            return result;
        }
        #endregion

        #region Prepare Popup
        /// <summary>
        /// Override this method for set some property of editor control.
        /// </summary>
        protected override void PreparePopup()
        {
            base.PreparePopup();

            if (mEditor != null && mEditor is ListBoxPopupEditor)
            {
                ((ListBoxPopupEditor)mEditor).EvenItemBackgroundColor = mEvenItemBackgroundColor;
                ((ListBoxPopupEditor)mEditor).OddItemBackgoundColor = mOddItemBackgoundColor;
            }
            #region Defensive tracing
            else
            {
                // cannot set value in null editor.
            }
            #endregion
        }
        #endregion

        #endregion

        #region Base methods

        #region On Selected Index Changed
        /// <summary>
        /// This method will be called after seleted index changed.
        /// </summary>
        protected virtual void OnSelectedIndexChanged() { }
        #endregion

        #region On Create Render Context
        /// <summary>
        /// Create a new render context instance.
        /// </summary>
        protected override EditBoxRenderContext OnCreateRenderContext()
        {
            PopupListBoxRenderContext result = new PopupListBoxRenderContext();
            result.Alignment = ContentAlignment.MiddleCenter;
            result.Multiline = false;
            result.TextStyle = TextStyle.Normal;

            return result;
        }
        #endregion

        #endregion

        #region Inner methods

        #region Find Item
        /// <summary>
        /// Iterate through all item, find an item that has the specified value. Use reflection if mLookupField is set
        /// </summary>
        /// <param name="value">This is the value stored in item.Value, not the ListboxItem itself</param>
        public virtual ListBoxItem FindItem(object value)
        {
            ListBoxItem result = null;

            if (value != null)
            {
                //search for matching item
                for (int i = 0; i < mItems.Count; i++)
                {
                    ListBoxItem li = FindMatchingItem(mItems[i], value);
                    if (li != null)
                    {
                        result = li;
                        break;
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Use recursive to find a matching item
        /// </summary>
        ListBoxItem FindMatchingItem(ListBoxItem item, object value)
        {
            ListBoxItem result = null;

            if (IsMatch(item.Value, value)) result = item;
            else
            {
                if ((item.Children != null) && (item.Children.Count > 0))
                {
                    for (int i = 0; i < item.Children.Count; i++)
                    {
                        ListBoxItem li = FindMatchingItem(item.Children[i], value);
                        if (li != null)
                        {
                            result = li;
                            break;
                        }
                    }//for
                }//if
            }//else

            return result;
        }

        /// <summary>
        /// Determine whether an item's value is same as the value. Use reflection if mLookupMember is set
        /// </summary>
        bool IsMatch(object itemValue, object value)
        {
            bool result = false;

            if ((itemValue == null) && (value == null)) result = true;
            else if (itemValue != null)
            {
                result = itemValue.Equals(value);
                #region Origin code
                //if (mLookupField == "")
                //{
                //    //result = (itemValue == value); //Inequality Equality problem
                //    result = itemValue.Equals(value);
                //}
                //else
                //{
                //    //reflect for the lookup member
                //    mLookupMember = null;
                //    ObjectReflector reflector = new ObjectReflector();
                //    MemberInfoCollection members = reflector.GetMembers(itemValue.GetType(), true, true, null, false, true);

                //    for (int i = 0; i < members.Count; i++)
                //    {
                //        if (members[i].Name == mLookupField)
                //        {
                //            mLookupMember = members[i];
                //            break;
                //        }
                //    }

                //    if (mLookupMember != null)
                //    {
                //        //reflect value
                //        object obj = null;
                //        if (mLookupMember is FieldInfo)
                //        {
                //            FieldInfo fi = mLookupMember as FieldInfo;
                //            obj = fi.GetValue(itemValue);
                //        }
                //        else if (mLookupMember is PropertyInfo)
                //        {
                //            PropertyInfo pi = mLookupMember as PropertyInfo;
                //            obj = pi.GetValue(itemValue, null);
                //        }

                //        //compare value
                //        //if (obj != null) result = (value == obj); //Inequality Equality problem
                //        if (obj != null) result = value.Equals(obj);
                //    }
                //}

                #endregion
            }

            return result;
        }
        #endregion

        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public PopupListBox() : base(typeof(ListBoxPopupEditor))
        {
            mDefaultPopupHeight = 150;
            mDefaultPopupWidth = 250;
            mIsShowPopupOnKeyPress = false;
            mShowDropButton = true;
        }
        #endregion
    }
}